#include "stdlib.hpp"
#include <purewell/types.hpp>
#include <purewell/mutex.hpp>

namespace purewell
{

static
pthread_mutex_t*
_createMutex(int type)
{
	pthread_mutexattr_t mattr;
	if ( 0 != pthread_mutexattr_init(&mattr) )
	{
		return NULL;
	}

	pthread_mutex_t* pmtex(NULL);

	do
	{
		if ( 0 != pthread_mutexattr_settype(&mattr, type) )
		{
			break;
		}

		if ( NULL == (pmtex = new pthread_mutex_t) )
		{
			break;
		}

		if ( 0 != pthread_mutex_init(pmtex, &mattr) )
		{
			break;
		}

		pthread_mutexattr_destroy(&mattr);
		return pmtex;

	} while (false);

	pthread_mutexattr_destroy(&mattr);
	if ( pmtex )
	{
		delete pmtex;
		pmtex = NULL;
	}

	return NULL;
}

PWMutex::PWMutex()
{
}

PWMutex::~PWMutex()
{
	if ( m_pData )
	{
		delete ((pthread_mutex_t*)m_pData);
		m_pData = NULL;
	}
}

void
PWMutex::release(PWMutex* lock)
{
	delete lock;
}

PWMutex*
PWMutex::create(int type)
{
	PWMutex* lock(new PWMutex);
	if ( !lock ) return NULL;

	pthread_mutex_t* mtx(_createMutex(type));
	if ( !mtx )
	{
		delete lock;
		return NULL;
	}

	lock->m_pData = mtx;

	return lock;
}

void
PWMutex::lock(void)
{
	pthread_mutex_lock((pthread_mutex_t*)m_pData);
}

void
PWMutex::unlock(void)
{
	pthread_mutex_unlock((pthread_mutex_t*)m_pData);
}

bool
PWMutex::lockTest(void)
{
	return (0 == pthread_mutex_trylock((pthread_mutex_t*)m_pData));
}

bool
PWMutex::lockTimeLimit(size_t msec)
{
	struct timespec ts;
	ts.tv_sec = msec / 1000;
	ts.tv_nsec = (msec % 1000) * 1000;
	return 0 == pthread_mutex_timedlock((pthread_mutex_t*)m_pData, &ts);
}

};//namespace purewell

